闲扯
早就想学 $DP$ 的优化了,咕了好久,今天终于还是学了学。
题面
Solution
考虑暴力 $DP$ 。
很容易可以得到一个递推式: $dp_i=\min_{j=0}^{i-1}(dp_j+(i-j+1+sum_i-sum_j-L)^2)$ 。
如果直接 $DP$ ,复杂度是 $n^2$ 的,显然不行,考虑优化。
由于原式中有平方项,所以会出现和 $i,j$ 均有关的转移项,普通的单调队列优化显然不行。
怎么办?这就要用到今天新学到的算法——斜率优化。
为了方便计算,我们做出如下约定: $a_i=i+sum_i,b_i=i+sum_i+L+1$ 。
考虑将原式中的 $\min$ 去掉,则:
$dp_i=dp_j+(a_i-b_j)^2$
$dp_i=dp_j+a_i^2-2a_ib_j+b_j^2$
$dp_j+b_j^2=2a_ib_j+dp_i-a_i^2$
我们将 $b_j$ 看作 $x$ ,将 $dp_j+b_j^2$ 看作 $y$ ,那么我们就得到了一个斜率为 $2*a_i$ 的直线。
那么我们要求的 $dp_i$ 就变成了这条直线的截距加上一个 $a_i^2$ 。
所以我们实际要求的是截距的最小值。
因为 $a_i$ 是单增的且求的是最小值,画图可以看出我们需要维护的是一个下凸壳。
我们每次将斜率小于 $2*a_i$ 的从单调队列中弹掉,那么队首就是我们要找的 $j$ 。
插入一个新的点时,我们将斜率大于该点与队尾的点构成的斜率的点弹出,再加入该点即可。(因为斜率是单增的,所以之后一定不会访问到这个点)
Code
1 |
|
总结
斜率优化感觉还没有入门啊,还要多最一些练习才行。